Skip to content

Conversation

unknownunknown1
Copy link
Contributor

@unknownunknown1 unknownunknown1 commented Sep 24, 2025

PR-Codex overview

This PR focuses on improving the voting mechanism in the DisputeKitClassicBase contract by introducing a counter to prevent double counting of committed votes. It also includes tests to verify that re-committing a vote does not increase the total committed count.

Detailed summary

  • Added a commitCount variable to track unique committed votes in DisputeKitClassicBase.
  • Updated the logic to increment round.totalCommitted by commitCount instead of the length of _voteIDs.
  • Added tests in KlerosCore_VotingTest to ensure re-committing a vote does not increase the total committed count.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • Bug Fixes

    • Prevents double-counting when recommitting votes: recommitting previously committed vote IDs no longer increases the total committed count.
    • Ensures recommits correctly update the stored commit value without affecting totals.
  • Tests

    • Added test coverage to validate recommit behavior, including unchanged totals and updated commit hashes.

Copy link

netlify bot commented Sep 24, 2025

Deploy Preview for kleros-v2-testnet ready!

Name Link
🔨 Latest commit 5b35be9
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet/deploys/68dc10cc6c58100008d27088
😎 Deploy Preview https://deploy-preview-2145--kleros-v2-testnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

netlify bot commented Sep 24, 2025

Deploy Preview for kleros-v2-testnet-devtools failed. Why did it fail? →

Name Link
🔨 Latest commit 5b35be9
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet-devtools/deploys/68dc10ccf69d6e00086cf456

Copy link

netlify bot commented Sep 24, 2025

Deploy Preview for kleros-v2-neo ready!

Name Link
🔨 Latest commit 5b35be9
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-neo/deploys/68dc10cca527a300082d0dba
😎 Deploy Preview https://deploy-preview-2145--kleros-v2-neo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adjusts commit accounting in DisputeKitClassicBase.castCommit to increment totals only for previously uncommitted voteIDs and adds tests validating recommit behavior without inflating totalCommitted while updating stored commit hashes.

Changes

Cohort / File(s) Summary
DisputeKit commit accounting
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
Introduces local commitCount to count only newly committed votes; updates totalCommitted by commitCount; preserves existing validations; allows recommit without increasing totals while updating stored commit.
Voting tests
contracts/test/foundry/KlerosCore_Voting.t.sol
Adds test: draw, commit once, recommit same voteIDs with new commit; asserts totalCommitted remains 1 and stored commit updated to keccak256(NO, salt).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Juror
  participant DK as DisputeKitClassicBase
  participant Storage as Vote Storage

  Note over Juror,DK: castCommit(voteIDs[], commit)
  Juror->>DK: castCommit(voteIDs, commit)
  activate DK
  DK->>DK: commitCount = 0
  loop For each voteID
    DK->>Storage: read commit[voteID]
    alt not previously committed (commit == 0)
      DK->>Storage: set commit[voteID] = newCommit
      DK->>DK: commitCount++
    else already committed
      DK->>Storage: update commit[voteID] = newCommit
    end
  end
  DK->>Storage: totalCommitted += commitCount
  deactivate DK
  DK-->>Juror: return
  Note over DK: Recommit updates hash but not totalCommitted
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

Type: Bug :bug:, Package: Contracts

Suggested reviewers

  • kemuru

Poem

A rabbit taps the chain with gentle wit,
“Count once, commit—recommit won’t overfit.”
Hashes hop anew, tallies stay still,
Burrows of bytes obey the bill.
With tidy paws and salted cheer,
The ledger’s clear—no double-count here. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title “fix(DK): multiple commit fix” follows the conventional commit format, clearly indicates that this is a fix in the DisputeKit component (DK) addressing multiple commits, and concisely summarizes the main functional change of preventing re-committed votes from being counted. It directly relates to the core update of tracking commitCount and adjusting totalCommitted to exclude already-committed votes. As such, the title is focused, specific, and informative for team members scanning the PR history.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/dk-multiple-commits

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df07fbb and 5b35be9.

📒 Files selected for processing (1)
  • contracts/test/foundry/KlerosCore_Voting.t.sol (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • contracts/test/foundry/KlerosCore_Voting.t.sol
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

253-257: Update NatSpec to reflect new single-commit semantics

Doc says commits can be overridden, but code now reverts on re-commit. Align the comment with behavior.

Apply:

-    /// @dev It can be called multiple times during the commit period, each call overrides the commits of the previous one.
+    /// @dev Each vote can be committed at most once per round. Attempts to re-commit an already committed vote revert with AlreadyCommittedThisVote().
🧹 Nitpick comments (1)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

277-281: Keep revert semantics predictable and save an sload per iteration

Check ownership before the “already committed” guard to avoid revealing commit status to non-owners and use a local Vote storage reference.

Apply:

-        for (uint256 i = 0; i < _voteIDs.length; i++) {
-            if (round.votes[_voteIDs[i]].commit != bytes32(0)) revert AlreadyCommittedThisVote();
-            if (round.votes[_voteIDs[i]].account != msg.sender) revert JurorHasToOwnTheVote();
-            round.votes[_voteIDs[i]].commit = _commit;
-        }
+        for (uint256 i = 0; i < _voteIDs.length; i++) {
+            Vote storage v = round.votes[_voteIDs[i]];
+            if (v.account != msg.sender) revert JurorHasToOwnTheVote();
+            if (v.commit != bytes32(0)) revert AlreadyCommittedThisVote();
+            v.commit = _commit;
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e827f63 and 6b74ebc.

📒 Files selected for processing (2)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (2 hunks)
  • contracts/test/foundry/KlerosCore_Voting.t.sol (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
🔇 Additional comments (2)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

763-764: LGTM: new error improves clarity

Error declaration is appropriate and non-breaking for storage.

contracts/test/foundry/KlerosCore_Voting.t.sol (1)

100-103: LGTM: asserts double-commit reverts as intended

Test correctly guards against re-commit attempts.

Consider adding one more check to ensure atomicity on mixed arrays (one already committed, one fresh) reverts and does not partially commit the fresh vote ID.

coderabbitai[bot]
coderabbitai bot previously approved these changes Sep 24, 2025
@jaybuidl
Copy link
Member

@coderabbitai create an issue for this

Copy link
Contributor

coderabbitai bot commented Sep 30, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for tracking the multiple commit fix
gh issue create \
  --title "Fix: Prevent multiple commits for the same vote in DisputeKit" \
  --body "This issue tracks the fix for allowing multiple commits for the same vote in DisputeKitClassicBase.

**Background:**
The DisputeKit was allowing jurors to submit multiple commits for the same vote IDs, which could lead to unexpected behavior.

**Solution:**
Added a guard in \`castCommit\` function to revert with \`AlreadyCommittedThisVote()\` error if a vote's commit is already set.

**Related PR:** #2145
**Requested by:** @jaybuidl" \
  --assignee jaybuidl

Length of output: 47


@jaybuidl I've created issue #2151 to track this fix: #2151

The issue documents the bug where multiple commits could be submitted for the same vote and the solution implemented in this PR.

@jaybuidl jaybuidl linked an issue Sep 30, 2025 that may be closed by this pull request
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (2)

281-283: Potential logic issue: Re-commit with same hash not properly handled.

The current logic only increments commitCount if commit == bytes32(0). However, if a juror calls castCommit twice with the same commit hash, the second call will:

  1. Not increment commitCount (correct)
  2. Overwrite commit with the same value (redundant but harmless)
  3. Emit CommitCast event again (potentially confusing)

While this doesn't break functionality, it allows redundant operations. Consider whether this is the desired behavior or if you should add an early check to prevent calling castCommit with an identical hash.

If you want to optimize, you could add:

 for (uint256 i = 0; i < _voteIDs.length; i++) {
     if (round.votes[_voteIDs[i]].account != msg.sender) revert JurorHasToOwnTheVote();
+    if (round.votes[_voteIDs[i]].commit == _commit) continue; // Skip if committing the same value
     if (round.votes[_voteIDs[i]].commit == bytes32(0)) {
         commitCount++;
     }
     round.votes[_voteIDs[i]].commit = _commit;
 }

277-278: Consider adding inline documentation.

The comment "Introduce a counter so we don't count a re-commited votes" is helpful. Consider expanding it to explain the invariant being maintained: totalCommitted represents the number of unique jurors who have committed at least once, not the total number of castCommit calls.

-        // Introduce a counter so we don't count a re-commited votes.
+        // Track how many votes are being committed for the first time in this call.
+        // totalCommitted represents unique votes committed, not total castCommit calls.
         uint256 commitCount;
contracts/test/foundry/KlerosCore_Voting.t.sol (1)

83-92: Consider adding edge case test coverage.

While the current test validates the core re-commit behavior, consider adding test cases for:

  1. Re-committing multiple voteIDs where some are new and some are re-commits
  2. Re-committing with the same hash (to verify idempotency)
  3. Verifying that CommitCast event is emitted correctly on re-commit

Example test for mixed scenario:

// Test re-committing with a mix of new and already-committed voteIDs
voteIDs = new uint256[](2);
voteIDs[0] = 0; // Already committed
voteIDs[1] = 1; // Not yet committed
vm.prank(staker1);
disputeKit.castCommit(disputeID, voteIDs, newCommit);

(, , , totalCommited, , ) = disputeKit.getRoundInfo(disputeID, 0, 0);
assertEq(totalCommited, 2, "totalCommited should be 2 (1 existing + 1 new)");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b74ebc and df07fbb.

📒 Files selected for processing (2)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1 hunks)
  • contracts/test/foundry/KlerosCore_Voting.t.sol (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests
  • GitHub Check: SonarCloud
🔇 Additional comments (2)
contracts/test/foundry/KlerosCore_Voting.t.sol (2)

38-38: LGTM: NO constant improves test readability.

The introduction of the NO constant (value 0) alongside the existing YES constant makes the test more readable and semantically clear, especially in the re-commit test scenario.


83-92: LGTM: Test correctly validates re-commit behavior.

This test segment properly verifies the fix:

  1. ✓ Confirms totalCommitted remains 1 after re-committing the same voteID
  2. ✓ Validates that the stored commit value is updated to the new hash
  3. ✓ Demonstrates that jurors can change their commit during the commit period

The test aligns with the implementation in DisputeKitClassicBase.sol and provides good coverage for the re-commit scenario.

Copy link

@jaybuidl jaybuidl merged commit 06db2d0 into dev Sep 30, 2025
13 of 20 checks passed
@jaybuidl jaybuidl deleted the fix/dk-multiple-commits branch September 30, 2025 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dispute kit: re-submitting a commitment is not counted correctly
2 participants